package asia.lxq.cic.service;


import asia.lxq.cic.aop.NeedAop;
import asia.lxq.cic.config.GlobalConfig;
import asia.lxq.cic.dao.AreaMapper;
import asia.lxq.cic.dao.GroupMapper;
import asia.lxq.cic.dao.UserMapper;
import asia.lxq.cic.entity.LoginUser;
import asia.lxq.cic.entity.Result;
import asia.lxq.cic.entity.StatusCode;
import asia.lxq.cic.entity.User;
import asia.lxq.cic.util.BCryptPasswordUtil;
import asia.lxq.cic.util.RedisUtil;
import asia.lxq.cic.util.TokenUtil;
import asia.lxq.cic.util.UserDirUtil;
import com.auth0.jwt.interfaces.Claim;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;


@Service
public class UserService implements UserDetailsService {

    @Autowired
    UserMapper userMapper;
//    @Autowired
//    AuthenticationManager authenticationManager;
    @Autowired
    AuthenticationConfiguration authenticationConfiguration;
    @Autowired
    RedisUtil redisUtil;
//    @Autowired
//    StringRedisTemplate stringRedisTemplate;
    @Autowired
    GroupMapper groupMapper;
    @Autowired
    AreaMapper areaMapper;


    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        LambdaQueryWrapper<User> wrapper=new LambdaQueryWrapper<>();
        wrapper.eq(User::getUsername,username);
        User user = userMapper.selectOne(wrapper);
        boolean aNull = Objects.isNull(user);
        if (aNull)throw new RuntimeException("用户名或密码错误");
        return new LoginUser(user);
    }

    public Result<Map<String, String>> login(Map<String,String> loginParam) throws Exception {
        AuthenticationManager authenticationManager = authenticationConfiguration.getAuthenticationManager();
        UsernamePasswordAuthenticationToken authenticationToken=
                new UsernamePasswordAuthenticationToken(loginParam.get("username"),loginParam.get("password"));
        Authentication authentication = authenticationManager.authenticate(authenticationToken);
        if (Objects.isNull(authentication)){
            throw new RuntimeException("登录失败");
        }
        LoginUser loginUser= (LoginUser) authentication.getPrincipal();
        User user=loginUser.getUser();
        Map<String,String> tokenPayloadMap=new HashMap<>();
        tokenPayloadMap.put("username",user.getUsername());
        tokenPayloadMap.put("userId",user.getUserId()+"");
        tokenPayloadMap.put("refresh_flag","false");
        Map<String,String> resultMap=new HashMap<>();
        resultMap.put("access_token", TokenUtil.tokenGenerator(tokenPayloadMap, GlobalConfig.TOKEN_EXPIRED_SPAN_OF_DAY));
        tokenPayloadMap.put("refresh_flag","true");
        resultMap.put("refresh_token",TokenUtil.tokenGenerator(tokenPayloadMap, GlobalConfig.REFRESH_TOKEN_EXPIRED_SPAN_OF_DAY));
        groupMapper.selectById(user.getGroupId());
        user.setGroup(groupMapper.selectById(user.getGroupId()));
        user.query(areaMapper);
        redisUtil.set(GlobalConfig.PRE_USERINFO_REDIS+user.getUserId(),user,60*60*24);
        return Result.success(resultMap, "登录成功");
    }

    public Result<Object> register(Map<String,String> registerParam){
        User registerUser=new User();
        registerUser.setUsername(registerParam.get("username"));
        registerUser.setPassword(BCryptPasswordUtil.BCryptPasswordEncoder(registerParam.get("password")));
        LambdaQueryWrapper<User> wrapper=new LambdaQueryWrapper<>();
        wrapper.eq(User::getUsername,registerUser.getUsername());
        User user = userMapper.selectOne(wrapper);
        if (user!=null) {
            return Result.buildOrigin(StatusCode.OTHER_ERR,null,"用户名“"+registerUser.getUsername()+"”已存在",false);
        }else {
            userMapper.insert(registerUser);
            wrapper.eq(User::getUsername,registerUser.getUsername());
            User userFromInsert=userMapper.selectOne(wrapper);
            File userDir=new File(UserDirUtil.getUserResDir(userFromInsert.getUserId()));
            System.out.printf("创建用户文件夹 “%s” : %s\n",userDir.getAbsolutePath(),userDir.mkdirs());
            return Result.buildOrigin(StatusCode.OK,null,"用户名“"+registerUser.getUsername()+"”注册成功",false);
        }
    }

    public Result<Object> logout(){
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        redisUtil.del(GlobalConfig.PRE_USERINFO_REDIS+authentication.getPrincipal());
        return Result.success("注销成功");
    }

    //todo 需要判断参数user和当前登录用户是否是同一个
    @NeedAop
    public Result<Object> updateUserBaseInfoWithAop(User user) {
        User userFromDB = userMapper.selectById(user.getUserId());
        userFromDB.setUsername(user.getUsername());
        userFromDB.setNickname(user.getNickname());
        userFromDB.setDescription(user.getDescription());
        userFromDB.setSex(user.getSex());
        userMapper.updateById(userFromDB);
        return Result.success(userFromDB, "修改成功");
    }
    public Result<Object> refreshToken(Map<String,String> param){
        String refreshTokenStr = param.get("refresh_token");
        Map<String,String> resultMap=new HashMap<>();
        if (refreshTokenStr==null||refreshTokenStr.equals("")) {
            return Result.buildOrigin(StatusCode.ILLEGAL_TOKEN,null,"refresh_token为空",false);
        }
        Map<String, Claim> claimMap;
        try{
            claimMap= TokenUtil.verifyToken(refreshTokenStr);
        }catch (Exception e){
            return Result.buildOrigin(StatusCode.ILLEGAL_TOKEN,e,"refresh_token错误",false);
        }
        boolean refreshFlag = Boolean.parseBoolean(claimMap.get("refresh_flag").asString());
        if (!refreshFlag)return Result.buildOrigin(StatusCode.ILLEGAL_TOKEN,null,"这不是refresh_token",false);
        String username = claimMap.get("username").asString();
        String userId = claimMap.get("userId").asString();
        Map<String,String> payloadMap=new HashMap<>();
        payloadMap.put("username",username);
        payloadMap.put("userId",userId);
        payloadMap.put("refresh_token","false");
        String newAccessToken = TokenUtil.tokenGenerator(payloadMap, GlobalConfig.TOKEN_EXPIRED_SPAN_OF_DAY);
        resultMap.put("access_token",newAccessToken);
        resultMap.put("refresh_token",refreshTokenStr);
        return Result.success(resultMap, "刷新refresh token成功");
    }

    @NeedAop
    public Result<Object> updateUserPic(MultipartFile resourceFile,Authentication authentication) {
        int userId=Integer.parseInt(authentication.getPrincipal()+"");
        File userPicFile=new File(UserDirUtil.getRealUserPic(userId));
        userPicFile.mkdirs();
        try {
            userPicFile.createNewFile();
            resourceFile.transferTo(userPicFile);
        } catch (IOException e) {
            return Result.error(e.getMessage());
        }
        return Result.success(userMapper.selectById(userId));
    }
}
